package YAPclient;

import YAPenvironment.YAPconstant;
import YAPenvironment.YAPconstant.Command;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JFrame;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.net.DatagramPacket;


/**
 * This is the window that opens when a client enters a lobby. It displays detailed information on this lobby and the
 * associated game, i.e. a list of all the players in this lobby plus their state (ready/unready), as well as the current
 * playground. As soon as the game starts, all components that now have become unnecessary are being removed to maximize the
 * playground's size.
 */

public class FormGameLobby extends JFrame implements ActionListener, KeyListener, ItemListener, MouseListener{ 


	private static final long serialVersionUID = -5519378205168050878L;

	private String sep = YAPconstant.C_SEPARATOR;
	
	private JButton btnSendMsg;
    private JLabel lblChat;
    private JLabel lblPlayers;
    private JToggleButton jtbReady;
    private JScrollPane jspChatOutput;
    private JScrollPane jspPlayers;
    private JList lstPlayersInLobby;
    private JList lstChatOutput;
    private CreatePanel createPanel;
    private LimitedTextField jtfChatInput;
    private Playground fPlayground;
    	
    
    /**
     * Creates a new instance of the class FormGameLobby
     * @param title Title of the FormGameLobby being created
     */
	public FormGameLobby(String title){
		
		if (DataModul.clPlayer != null){
			
			addWindowListener(new ExitListener());
			
			setTitle("YAP: "+DataModul.clPlayer.getName());
			setIconImage(YAPconstant.ICONIMAGE);

			createGUI();
		}
	}
	
	private void createGUI() {

		/*
		 * Initialize
		 */
		fPlayground = new Playground(GameInformation.GameMode.lobby);
	    lblChat = new JLabel();
	    lblPlayers = new JLabel();
        jspChatOutput = new JScrollPane();
        jspPlayers = new JScrollPane();
        btnSendMsg = new JButton();
        jtbReady = new JToggleButton();
        createPanel = new CreatePanel();
        jtfChatInput = new LimitedTextField(new SetMaxText(50));
        lstChatOutput =  new javax.swing.JList(DataModul.flo.getChatListModel());
        lstPlayersInLobby = new JList(DataModul.flo.getPlayersInLobbyListModel());

        lblChat.setText("Chat:");
	        
	    jspChatOutput.setViewportView(lstChatOutput);
	    lstChatOutput.addMouseListener(this);
	    jspChatOutput.setPreferredSize(new Dimension(jspChatOutput.getPreferredSize().width+45,jspChatOutput.getPreferredSize().height));
	        
	    btnSendMsg.setText("Chat");
	    btnSendMsg.addActionListener(this);

	    lblPlayers.setText("Players in Lobby:");
	        
	    jspPlayers.setViewportView(lstPlayersInLobby);
	        
	    lstPlayersInLobby.addMouseListener(this);

	    fPlayground.setMaximumSize(new java.awt.Dimension(YAPconstant.FGLO_PLAYGROUNDSIZE, YAPconstant.FGLO_PLAYGROUNDSIZE));
	    fPlayground.setMinimumSize(new java.awt.Dimension(YAPconstant.FGLO_PLAYGROUNDSIZE, YAPconstant.FGLO_PLAYGROUNDSIZE));
	    fPlayground.setPreferredSize(new java.awt.Dimension(YAPconstant.FGLO_PLAYGROUNDSIZE, YAPconstant.FGLO_PLAYGROUNDSIZE));

	    jtbReady.setText("ready");
	    jtbReady.addItemListener(this);
	        
	    /*
	     * SetFocusable
	     */
	    btnSendMsg.setFocusable(true);
	    jtbReady.setFocusable(true);
	    jtfChatInput.setFocusable(true);
	    lstPlayersInLobby.setFocusable(true);
	    fPlayground.setFocusable(true);
	    lstChatOutput.setFocusable(true);
			 
	    /*
	     * Add KeyListener
	     */
	    btnSendMsg.addKeyListener(this);
	    jtbReady.addKeyListener(this);
	    jtfChatInput.addKeyListener(this);
	    lstPlayersInLobby.addKeyListener(this);
	    fPlayground.addKeyListener(this);
	    lstChatOutput.addKeyListener(this);
			 
	    setJMenuBar(new YAPMenuBar(true));
			 
	    if(!DataModul.gInfo.playerIsHost()){
	    	createPanel.disable();
	    }


	    /*
		 * Layout
		 */
	    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
	    getContentPane().setLayout(layout);
	    layout.setAutoCreateContainerGaps(true);
	    layout.setAutoCreateGaps(true);
	    layout.setHorizontalGroup(
	    	layout.createSequentialGroup()
	    		.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	    			.addComponent(fPlayground, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
	    			.addComponent(jtbReady, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE)
	    			.addComponent(createPanel,javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE,Short.MAX_VALUE))
	    		.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                .addComponent(lblPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
	                .addComponent(jspChatOutput,javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE)
	                .addComponent(jspPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 205, javax.swing.GroupLayout.PREFERRED_SIZE)
	                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
	                    .addComponent(jtfChatInput)
	                    .addComponent(btnSendMsg, javax.swing.GroupLayout.PREFERRED_SIZE,  javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
	                .addComponent(lblChat, javax.swing.GroupLayout.PREFERRED_SIZE, 205, javax.swing.GroupLayout.PREFERRED_SIZE)));
	    layout.setVerticalGroup(
	    	layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	            .addGroup(layout.createSequentialGroup()
	                .addComponent(lblChat)
	                .addComponent(jspChatOutput)
	                .addGroup(layout.createParallelGroup()
	                    .addComponent(jtfChatInput, javax.swing.GroupLayout.PREFERRED_SIZE,  27, javax.swing.GroupLayout.PREFERRED_SIZE)
	                    .addComponent(btnSendMsg, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE ,javax.swing.GroupLayout.PREFERRED_SIZE))
	                    .addGap(20, 20, 20)
	                    .addComponent(lblPlayers)
	                    .addComponent(jspPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE))
	                .addGroup(layout.createSequentialGroup()
	                    .addComponent(fPlayground, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
	                    .addGap(10,10,10)
	                    .addComponent(jtbReady)
	                    .addGap(25,25,25)
	                    .addComponent(createPanel,this.createPanel.getMinimumSize().height, this.createPanel.getPreferredSize().height,this.createPanel.getPreferredSize().height)));
	        
	   layout.setHonorsVisibility(true);
	   pack();
	   setResizable(true);
	   setVisible(true);
	   
	}


	/**
	  * @return this form's {@link CreatePanel}
	  */
	public CreatePanel getCreatePanel() {
		return createPanel;
	}

	
	/**
	 * @param createPanel The {@link CreatePanel} to be displayed in this form
	 */
	public void setCreatePanel(CreatePanel createPanel) {
		this.createPanel = createPanel;
	} 
	

	/**
	 * Rotates this form's playground
	 * @param siTime 
	 * @param siPiMult
	 */
	public void rotatePlayground(int siTime, int siPiMult){
		fPlayground.setAutomaticRotation(siTime*1000, Math.PI*siPiMult);
	}
	
	
	/**
	 * Resets the playground's timer
	 */
	public void resetPGTimer(){
		if (fPlayground != null){
			fPlayground.resetTimer();
		}
	}
	
	/**
	 * Stops the playground's timer
	 */
	public void stopPGTimer(){
		if (fPlayground != null){
			fPlayground.stopTimer();
		}
	}
	
	/**
	 * Sets jtbReady to 'ready'
	 */
	public void selectReady(){
		jtbReady.setSelected(true);
	}
	
	
	/**
	 * Sets the jtbReady to 'unready'
	 */
	public void selectUnready(){
		jtbReady.setSelected(false);
	}
	
	
	/**
	 * Sets this form into game mode, i.e. createPanel and jtbReady are no longer visible
	 */
	public void switchToGameMode(){
		this.jtbReady.setVisible(false);
		this.createPanel.setVisible(false);
	}
		
	/**
	 * Sets this form into lobby mode, i.e. createPanel and jtbReady become visible again
	 */
	public void switchToLobbyMode(){
		this.jtbReady.setVisible(true);
		this.createPanel.setVisible(true);
		this.validate();
	}
	
	
	/**
	 * Sends the content of the chat input field to the server (using the {@link ParseThread}'s sendChatMsg method)
	 * @param strMsg The message that is being sent
	 */
	public void sendChat(String strMsg){
		try {
			DataModul.parseThread.sendChatMsg(jtfChatInput.getText());
			jtfChatInput.setText("");
		} catch (Exception e) {
			if(YAPconstant.C_DEBUG) { e.printStackTrace(); }
			if(DataModul.flo.getChatListModel() != null)
				DataModul.flo.getChatListModel().addElement("Couldn't send message");
		}
	}
	
	
	/**
	 * Automatically scrolls the chat history when receiving messages
	 */
	public void adjustChatScrollBar() {
		jspChatOutput.validate();
		jspChatOutput.getVerticalScrollBar().setValue(jspChatOutput.getVerticalScrollBar().getMaximum());
	}


	private void sendPackage(String direction){
		String sep = YAPconstant.C_SEPARATOR;
		byte[] data = (YAPconstant.Command.sendKey+sep+direction+sep+DataModul.gInfo.getName()+sep +DataModul.clPlayer.getName()+sep).getBytes();
		send(data);
	}
	
	private void sendNomove(){
		String sep = YAPconstant.C_SEPARATOR;
		byte[] data = (YAPconstant.Command.noMove+sep+DataModul.gInfo.getName()+sep +DataModul.clPlayer.getName()+sep).getBytes();
		for(int i=0; i<5; i++)
			send(data);
	}
	
	private void send(byte[] data){
		try {
			DatagramPacket packet =  new DatagramPacket(
					data, data.length,
					DataModul.hostAddress, YAPconstant.C_MULTICASTPORT1
					);
			DataModul.dSocket.send(packet);
		} catch (Exception e) {
			if(YAPconstant.C_DEBUG){ e.printStackTrace(); }
		}
	}
	
	
	/**
	 * Handles user input from btnSendMessage, which results in a chat message being sent to the server
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource()==btnSendMsg){
			sendChat(jtfChatInput.getText());
		}
	}
	
	
	/**
	 * Processes in-game keyboard input from a user, i.e. sends 'left' or 'right' to the server
	 * if VK_LEFT or VK_RIGHT are being pressed
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyPressed(KeyEvent e) {	
		
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			sendPackage("left");
//			ks.setLeftKey();
		}
		else if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			sendPackage("right");
//			ks.setRightKey();
		}
		else if(e.getSource()!=jtfChatInput){
				if(e.getKeyCode()==KeyEvent.VK_P || e.getKeyCode()==KeyEvent.VK_PAUSE){
					DataModul.parseThread.writeMessage(Command.pause+sep);
				}
		}
	}
	

	/**
	 * Gives users the possibility to send chat messages by hitting ENTER (same result as clicking on btnSend)
	 * and sends 'nomove' to the server if VK_LEFT or VK_RIGHT are released
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyReleased(KeyEvent e) {
		if(e.getSource()==jtfChatInput){
			if(e.getKeyCode()==KeyEvent.VK_ENTER){
				sendChat(jtfChatInput.getText());
			}
		}
//		if(e.getKeyCode()==KeyEvent.VK_LEFT){
//			ks.releaseLeftKey();
//		}else if (e.getKeyCode()==KeyEvent.VK_RIGHT){
//			ks.releaseRightKey();
//		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT || e.getKeyCode()==KeyEvent.VK_RIGHT){
				sendNomove();
		}
		
	}
	
	@Override
	public void keyTyped(KeyEvent e) {}	
	

	/** 
	 * Sets the player's state on the server to ready if jtbReady is selected
	 * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) 
	 */
	@Override
	public void itemStateChanged(ItemEvent e) {
		if (e.getSource().equals(jtbReady)){
			if(e.getStateChange() == ItemEvent.SELECTED)
	        {
	            DataModul.parseThread.writeMessage(Command.setReady.toString()+sep);
	        }
			else
			{
				DataModul.parseThread.writeMessage(Command.setUnReady.toString()+sep);
			}
		}
	}

	
	/**
	 * Gives users the possibility to select the player they want to whisper to
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseClicked(MouseEvent evt) {
		if (evt.getClickCount() == 2) {
			if(evt.getSource()==lstPlayersInLobby)
				FormLobbyOverview.setWhisper(jtfChatInput, lstPlayersInLobby);
			else if(evt.getSource()==lstChatOutput)
				FormLobbyOverview.setWhisper(jtfChatInput, lstChatOutput);
		}
	}

	
	@Override
	public void mousePressed(MouseEvent e) {}
	
	@Override
	public void mouseReleased(MouseEvent e) {}
	
	@Override
	public void mouseEntered(MouseEvent e) {}
	
	@Override
	public void mouseExited(MouseEvent e) {}


	/**
	 * This class handles window closing events received from instances of the class {@link FormGameLobby},
	 * i.e. the user leaves this lobby
	 */
	class ExitListener extends WindowAdapter{
		String sep = YAPconstant.C_SEPARATOR;
		public void windowClosing(WindowEvent event){
			if(DataModul.udpReceiver!=null)
				DataModul.udpReceiver.close();
			DataModul.parseThread.writeMessage(Command.leaveLobby+sep);
		}
	}

	
}

@Deprecated
class KeyStore {
	boolean m_IsLeftKey = false;
	boolean m_IsRightKey = false;
	
	public void setLeftKey(){
		m_IsLeftKey = true;
		sendKeyState();
	}
	public void setRightKey(){
		m_IsRightKey = true;
		sendKeyState();
	}
	public void releaseRightKey(){
		m_IsRightKey = false;
		sendKeyState();
	}
	public void releaseLeftKey(){
		m_IsLeftKey = false;
		sendKeyState();
	}
	private void sendKeyState(){
		String sep = YAPconstant.C_SEPARATOR;
		if (!(m_IsLeftKey || m_IsRightKey) || (m_IsLeftKey && m_IsRightKey)){
			DataModul.parseThread.writeMessage(Command.noMove.toString()+sep);
			
		}
		else if (m_IsLeftKey){
			DataModul.parseThread.writeMessage(Command.sendKey+sep+"left");
		}
		else if (m_IsRightKey){
			DataModul.parseThread.writeMessage(Command.sendKey+sep+"right");
		}
	}
}
